﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WineStore.DAL;
using System.Data;
using System.IO;
using WineStore.Models;
using PagedList;
using PagedList.Mvc;
using System.Data.Entity;


namespace WineStore.Controllers
{
    
    public class ProductController : Controller
    {
        // Show Product
        public ViewResult ShowProduct(string sortOrder, string currentFilter, string searchString, int? page)
        {
            ViewBag.CurrentSort = sortOrder;
            ViewBag.SortPriceParm = sortOrder == "price asc" ? "price desc" : "price asc";

            if (Request.HttpMethod == "GET")
            {
                searchString = currentFilter;
            }
            else
            {
                page = 1;
            }
            ViewBag.CurrentFilter = searchString;

            using (var db = new WineDbContext())
            {
                var products = db.Products
                               .Include(p => p.Category);

                if (!String.IsNullOrEmpty(searchString))
                {
                    products = products.Where(p => p.ProductName.ToUpper().Contains(searchString.ToUpper()));
                }
                switch (sortOrder)
                {
                    case "price desc":
                        products = products.OrderByDescending(p => p.ProductPrice);
                        break;
                    case "price asc":
                        products = products.OrderBy(p => p.ProductPrice);
                        break;
                    default:
                        products = products.OrderByDescending(p => p.ProductId);
                        break;
                }

                int pageSize = 3;
                int pageNumber = (page ?? 1);

                // Thiet lap thuoc tinh khi phan trang
                PagedListRenderOptions pro = new PagedListRenderOptions();
                pro.MaximumPageNumbersToDisplay = 5;
                pro.LinkToLastPageFormat = "Last";
                pro.DisplayLinkToLastPage = true;
                pro.LinkToFirstPageFormat = "First";
                pro.DisplayLinkToFirstPage = true;
                pro.LinkToNextPageFormat = ">>";
                pro.DisplayLinkToNextPage = true;
                pro.LinkToPreviousPageFormat = "<<";
                pro.DisplayLinkToPreviousPage = true;

                ViewBag.Pro = pro;

                return View(products.ToPagedList(pageNumber, pageSize));
            }
        }

        // Show Product Partial
        public ViewResult ShowProductPartial(string sortOrder, string currentFilter, string searchString, int? page)
        {
            ViewBag.CurrentSort = sortOrder;
            ViewBag.SortPriceParm = sortOrder == "price asc" ? "price desc" : "price asc";

            if (Request.HttpMethod == "GET")
            {
                searchString = currentFilter;
            }
            else
            {
                page = 1;
            }
            ViewBag.CurrentFilter = searchString;

            using (var db = new WineDbContext())
            {
                var products = db.Products
                               .Include(p => p.Category);

                if (!String.IsNullOrEmpty(searchString))
                {
                    products = products.Where(p => p.ProductName.ToUpper().Contains(searchString.ToUpper()));
                }
                switch (sortOrder)
                {
                    case "price desc":
                        products = products.OrderByDescending(p => p.ProductPrice);
                        break;
                    case "price asc":
                        products = products.OrderBy(p => p.ProductPrice);
                        break;
                    default:
                        products = products.OrderByDescending(p => p.ProductId);
                        break;
                }

                int pageSize = 3;
                int pageNumber = (page ?? 1);

                // Thiet lap thuoc tinh khi phan trang
                PagedListRenderOptions pro = new PagedListRenderOptions();
                pro.MaximumPageNumbersToDisplay = 5;
                pro.LinkToLastPageFormat = "Last";
                pro.DisplayLinkToLastPage = true;
                pro.LinkToFirstPageFormat = "First";
                pro.DisplayLinkToFirstPage = true;
                pro.LinkToNextPageFormat = ">>";
                pro.DisplayLinkToNextPage = true;
                pro.LinkToPreviousPageFormat = "<<";
                pro.DisplayLinkToPreviousPage = true;

                ViewBag.Pro = pro;

                return View(products.ToPagedList(pageNumber, pageSize));
            }
        }

        // Create Product (Goi tu trang ShowProduct)
        [HttpGet]
        public ActionResult CreateProduct()
        {
            PopulateCategoriesDropDownList();
            return View();
        }

        /* Thêm một thực thể Proudct được tạo bởi ASP.NET MVC model binder vào tập Products và lưu vào CSDL.
           (Model binder là một tính năng có trong ASP.NET MVC cho phép dễ dàng làm việc với dữ liệu được gửi
           lên từ một form; trong đó một model binder sẽ chuyển các giá trị gửi lên từ form thành kiểu có trong
           .NET Framework và đưa chúng vào các action method dưới dạng các tham số. Trong trường hợp này, model
           binder khởi tạo một thực thể Product và dùng các giá trị từ tập FormCollection.*/
        // Create Product (Goi tu trang Create Product)
        [HttpPost]
        public ActionResult CreateProduct(Product product, HttpPostedFileBase ProductImage)
        {
            try
            {
                // Validate in server
                if (ModelState.IsValid)
                {
                    // Luu anh len server
                    string path = System.IO.Path.Combine(Server.MapPath("~/Content/Images/Products"), System.IO.Path.GetFileName(ProductImage.FileName));
                    ProductImage.SaveAs(path);
                    // Luu product vao database 
                    product.ProductImage = ProductImage.FileName;
                    using (var db = new WineDbContext())
                    {
                        db.Entry(product).State = EntityState.Added;
                        db.SaveChanges();
                        return RedirectToAction("ShowProduct", "Product");
                    }
                }
            }
            catch (DataException)
            {
                ModelState.AddModelError("", "Unable to save changes");
            }
            PopulateCategoriesDropDownList(product.CategoryId);
            return View(product);
        }

        // Show Detail Product (Goi tu trang ShowProduct)
        [HttpGet]
        public ActionResult EditProduct(int id = 0)
        {
            Product product = null;
            using (var db = new WineDbContext())
            {
                product = db.Products.Find(id);
                if (product == null)
                {
                    return HttpNotFound();
                }
            }
            PopulateCategoriesDropDownList(product.CategoryId);
            return View(product);
        }

        /* Khi phương thức SaveChanges được gọi, cờ Modified làm cho Entity Framework cập nhật dòng tương ứng
           trong CSDL. Tất cả các cột sẽ được cập nhật, bao gồm cả các cột người dùng không thay đổi.*/
        // Edit Product (Goi tu trang Edit Product)
        [HttpPost]
        public ActionResult EditProduct(Product product, HttpPostedFileBase ProductImage)
        {
            try
            {
                // Lay ve duong dan anh cu
                product.ProductImage = (new WineDbContext().Products.Find(product.ProductId)).ProductImage;

                if (ModelState.IsValidField("ProductName") && ModelState.IsValidField("ProductPrice") && ModelState.IsValidField("DateAdd"))
                {
                    // Neu update anh moi thi thuc hien khoi lenh trong than cau lenh if
                    if (ProductImage != null)
                    {
                        // Xoa anh cu tren server
                        FileInfo fileInfo = new FileInfo(Server.MapPath("~/Content/Images/Products/" + product.ProductImage));
                        if (fileInfo != null)
                        {
                            fileInfo.Delete();
                        }
                        // Luu anh moi len server
                        string path = System.IO.Path.Combine(Server.MapPath("~/Content/Images/Products"), System.IO.Path.GetFileName(ProductImage.FileName));
                        ProductImage.SaveAs(path);
                        // Luu duong dan anh vao database 
                        product.ProductImage = ProductImage.FileName;
                    }

                    using (var db = new WineDbContext())
                    {
                        db.Entry(product).State = EntityState.Modified;
                        db.SaveChanges();
                        return RedirectToAction("ShowProduct", "Product");
                    }
                }
            }
            catch (DataException)
            {
                ModelState.AddModelError("", "Unable to save changes");
            }
            PopulateCategoriesDropDownList(product.CategoryId);
            return View(product);
        }


        /* Đoạn lệnh dưới đây nhận thêm vào một tham số tùy chọn kiểu boolean chỉ ra nó có phải được gọi sau
           một lệnh lưu dữ liệu thất bại. Tham số này sẽ là null (hoặc false) khi HttpGet Delete được gọi để
           phản hồi một yêu cầu bình thường. Khi nó được gọi bởi HttpPost Delete để phản hồi một lỗi cập nhật,
           tham số này sẽ là true và một thông báo lỗi sẽ được chuyển đến cho view tương ứng.*/
        // Delete Product (Goi tu trang Show Product)
        [HttpGet]
        public ActionResult DeleteProduct(int id, bool? saveChangesError)
        {
            Product product = null;
            if (saveChangesError.GetValueOrDefault())
            {
                ViewBag.ErrorMessage = "Unable to save changes";
            }
            using (var db = new WineDbContext())
            {
                product = db.Products.Find(id);
                if (product == null)
                {
                    return HttpNotFound();
                }
            }
            return View(product);
        }

        // Delete Product (Goi tu trang Delete Product)
        [HttpPost]
        public JsonResult DeleteProduct(int id)
        {
            Product product = null;
            try
            {
                using (var db = new WineDbContext())
                {
                    product = db.Products.Find(id);
                    // Xoa anh tren server
                    FileInfo fileInfo = new FileInfo(Server.MapPath("~/Content/Images/Products/" + product.ProductImage));
                    if (fileInfo != null)
                    {
                        fileInfo.Delete();
                    }
                    db.Entry(product).State = EntityState.Deleted;
                    db.SaveChanges();
                }

            }
            catch (DataException)
            {

            }
            var results = new
            {
                Message = Server.HtmlEncode(product.ProductName) +
                    " has been removed!",
                Id = id
            };

            return Json(results);
        }

        // Autocomplete for textbox search 
        [HttpGet]
        public ActionResult Autocomplete(string term)
        {
            using (var db = new WineDbContext())
            {
                var productNames = from p in db.Products
                                   select p.ProductName;
                string[] items = productNames.ToArray();

                var filteredItems = items.Where(
                    item => item.IndexOf(term, StringComparison.InvariantCultureIgnoreCase) >= 0
                    );
                return Json(filteredItems, JsonRequestBehavior.AllowGet);
            }
        }

        // Bind du lieu len DropDownList
        private void PopulateCategoriesDropDownList(object selectedCategory = null)
        {
            using (var db = new WineDbContext())
            {
                var categoriesQuery = from c in db.Categories
                                      orderby c.CategoryName
                                      select c;
                ViewBag.CategoryId = new SelectList(categoriesQuery.ToList(), "CategoryId", "CategoryName", selectedCategory);
            }
        }
    }
}

/* Trong các thao tác thêm, sửa, xóa yêu cầu hai phương thức action. Phương thức dùng để phản hồi lại yêu cầu 
   GET hiển thị một view cho phép người dùng xác nhận lại thao tác , nếu người dùng chấp nhận, một yêu cầu POST
   sẽ được tạo. Khi đó, phương thức HttpPost được gọi và dữ liệu khi đó mới thực sự được thêm, sửa, xóa*/
